package com.jichangxiu.generator.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.generator.constant.GeneratorConstants;
import com.jichangxiu.generator.entity.vo.TableVo;
import com.jichangxiu.common.properties.JcxProperties;
import com.jichangxiu.common.utils.StrUtils;
import com.jichangxiu.framework.utils.NoUtils;
import com.jichangxiu.framework.utils.SecurityUtils;
import com.jichangxiu.generator.entity.dto.add.AddGenColumn;
import com.jichangxiu.generator.entity.dto.add.AddGenRow;
import com.jichangxiu.generator.entity.vo.GenColumnVo;
import com.jichangxiu.generator.entity.vo.GenRowVo;
import com.jichangxiu.generator.entity.vo.GenTemplateVo;
import com.jichangxiu.generator.enums.GenType;
import com.jichangxiu.generator.enums.TemplateCategory;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * VelocityUtils:
 *
 * @author Jcx
 * @create 2024-06-30 14:19
 */
public class VelocityUtils {

    public static HashSet<String> getImportList(GenRowVo genRowVo) {
        HashSet<String> importList = new HashSet<>();
        if (StrUtil.isNotEmpty(genRowVo.getChildRowId())) {
            importList.add("java.util.List");
        }
        List<GenColumnVo> genColumnVoList = genRowVo.getGenColumnVoList();
        for (GenColumnVo genColumnVo : genColumnVoList) {
            if (!genColumnVo.isSuperColumn() && GeneratorConstants.TYPE_DATE.equals(genColumnVo.getJavaType())) {
                importList.add("java.util.Date");
                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
            } else if (!genColumnVo.isSuperColumn() && GeneratorConstants.TYPE_BIG_DECIMAL.equals(genColumnVo.getJavaType())) {
                importList.add("java.math.BigDecimal");
            }
        }
        return importList;
    }

    public static String getDictCodeList(GenRowVo genRowVo, boolean flag) {
        Set<String> dictCodeList = new HashSet<>();
        addDictList(dictCodeList, genRowVo.getGenColumnVoList(), flag);
        if (ObjectUtil.isNotEmpty(genRowVo.getChildRowId())) {
            addDictList(dictCodeList, genRowVo.getChildRowVo().getGenColumnVoList(), flag);
        }
        return StringUtils.join(dictCodeList, ", ");
    }

    public static void addDictList(Set<String> dictCodeList, List<GenColumnVo> genColumnVoList, boolean flag) {
        for (GenColumnVo genColumnVo : genColumnVoList) {
            if (!genColumnVo.isSuperColumn() && StrUtil.isNotEmpty(genColumnVo.getDictCode())
                    && StringUtils.equalsAny(genColumnVo.getHtmlType(), new String[]{GeneratorConstants.HTML_SELECT, GeneratorConstants.HTML_RADIO, GeneratorConstants.HTML_CHECKBOX})) {
                if (flag) {
                    dictCodeList.add("'" + genColumnVo.getDictCode() + "'");
                } else {
                    dictCodeList.add(genColumnVo.getDictCode());
                }
            }
        }
    }

    public static void setMenuInfoToVelocityContext(VelocityContext context, GenRowVo genRowVo, boolean type) {
        String parentMenuId = genRowVo.getMenuId();
        if (type) {
            context.put("parentMenuId", parentMenuId);

            context.put("firstMenuId", IdWorker.getIdStr());
            context.put("secondMenuId", IdWorker.getIdStr());
            context.put("thirdMenuId", IdWorker.getIdStr());
            context.put("fourthMenuId", IdWorker.getIdStr());
            context.put("fifthMenuId", IdWorker.getIdStr());

            context.put("firstMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("secondMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("thirdMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("fourthMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("fifthMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));

            context.put("firstPowerId", IdWorker.getIdStr());
            context.put("secondPowerId", IdWorker.getIdStr());
            context.put("thirdPowerId", IdWorker.getIdStr());
            context.put("fourthPowerId", IdWorker.getIdStr());
            context.put("fifthPowerId", IdWorker.getIdStr());
        } else {
            context.put("childParentMenuId", parentMenuId);

            context.put("childFirstMenuId", IdWorker.getIdStr());
            context.put("childSecondMenuId", IdWorker.getIdStr());
            context.put("childThirdMenuId", IdWorker.getIdStr());
            context.put("childFourthMenuId", IdWorker.getIdStr());
            context.put("childFifthMenuId", IdWorker.getIdStr());

            context.put("childFirstMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("childSecondMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("childThirdMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("childFourthMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));
            context.put("childFifthMenuNo", NoUtils.createNo(SecurityUtils.getTenantId(), "menu"));

            context.put("childFirstPowerId", IdWorker.getIdStr());
            context.put("childSecondPowerId", IdWorker.getIdStr());
            context.put("childThirdPowerId", IdWorker.getIdStr());
            context.put("childFourthPowerId", IdWorker.getIdStr());
            context.put("childFifthPowerId", IdWorker.getIdStr());
        }
    }

    public static String getFileName(GenTemplateVo genTemplateVo, GenRowVo genRowVo) {
        String category = genTemplateVo.getCategory();
        // 文件名称
        String fileName = "";
        // 包路径
        String packageName = genRowVo.getPack();
        // 模块名
        String moduleName = genRowVo.getModule();
        // 大写类名
        String bigClazz = genRowVo.getBigClazz();
        // 业务名称
        String businessName = genRowVo.getBusiness();
        String javaPath = GeneratorConstants.PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
        String mybatisPath = GeneratorConstants.MYBATIS_PATH + "/" + moduleName;
        String vuePath = "vue";
        if (TemplateCategory.JAVA_ACTION.name().equals(category)) {
            fileName = StrUtils.format("{}/action/{}Action.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_BO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/bo/{}Bo.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_ADD_DTO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/dto/add/Add{}.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_EDIT_DTO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/dto/edit/Edit{}.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_QUERY_DTO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/dto/query/Query{}.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_PO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/po/{}.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_ENTITY_VO.name().equals(category)) {
            fileName = StrUtils.format("{}/entity/vo/{}Vo.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_MAPPER.name().equals(category)) {
            fileName = StrUtils.format("{}/mapper/{}Mapper.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_SERVICE.name().equals(category)) {
            fileName = StrUtils.format("{}/service/{}Service.java", javaPath, bigClazz);
        } else if (TemplateCategory.JAVA_SERVICE_IMPL.name().equals(category)) {
            fileName = StrUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, bigClazz);
        } else if (TemplateCategory.XML_MAPPER.name().equals(category)) {
            fileName = StrUtils.format("{}/{}Mapper.xml", mybatisPath, bigClazz);
        } else if (TemplateCategory.SQL_INSERT_MENU.name().equals(category)) {
            fileName = businessName + "Menu.sql";
        } else if (TemplateCategory.JS_API.name().equals(category)) {
            fileName = StrUtils.format("{}/api/{}/{}/index.js", vuePath, moduleName, businessName);
        } else if (TemplateCategory.VUE_INDEX.name().equals(category)) {
            fileName = StrUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
        } else if (TemplateCategory.VUE_FORM.name().equals(category)) {
            fileName = StrUtils.format("{}/views/{}/{}/form.vue", vuePath, moduleName, businessName);
        }
        return fileName;
    }

    public static AddGenRow initAddGenRow(TableVo tableVo) {
        JcxProperties.GeneratorProperties generatorProperties = Constants.JCX_PROPERTIES.getGeneratorProperties();
        AddGenRow addGenRow = new AddGenRow();
        addGenRow.setId(IdWorker.getIdStr());
        addGenRow.setNo(NoUtils.createNo(SecurityUtils.getTenantId(), "row"));
        addGenRow.setName(tableVo.getName());
        addGenRow.setComment(tableVo.getComment());
        addGenRow.setCategoryId(generatorProperties.getDefaultCategoryId());
        addGenRow.setChildRowId(null);
        addGenRow.setChildColumnId(null);
        addGenRow.setPack(generatorProperties.getPack());
        String className = GeneratorUtils.convertClassName(tableVo.getName());
        addGenRow.setClazz(StringUtils.uncapitalize(className));
        addGenRow.setBigClazz(StringUtils.capitalize(className));
        addGenRow.setModule(GeneratorUtils.getModuleName(generatorProperties.getPack()));
        String businessName = GeneratorUtils.getBusinessName(tableVo.getName());
        addGenRow.setBusiness(StringUtils.uncapitalize(businessName));
        addGenRow.setBigBusiness(StringUtils.capitalize(businessName));
        addGenRow.setAuthor(generatorProperties.getAuthor());
        addGenRow.setAbility(tableVo.getComment());
        addGenRow.setType(GenType.ZIP.name());
        addGenRow.setPath("/");
        addGenRow.setMenuId(generatorProperties.getDefaultMenuId());
        addGenRow.setGenerated(false);
        addGenRow.setOptions(null);
        addGenRow.setRemark(tableVo.getComment());
        List<AddGenColumn> addGenColumnList = new ArrayList<>();
        tableVo.getColumnVoList().forEach(columnVo -> {
            AddGenColumn addGenColumn = new AddGenColumn();
            addGenColumn.setRowId(addGenRow.getId());
            addGenColumn.setName(columnVo.getName());
            addGenColumn.setComment(columnVo.getComment());
            addGenColumn.setColumnType(GeneratorUtils.getDbType(columnVo.getColumnType()));
            addGenColumn.setJavaType(GeneratorUtils.getJavaType(columnVo.getColumnType()));
            String columnName = StrUtils.toCamelCase(columnVo.getName());
            addGenColumn.setJavaField(StringUtils.uncapitalize(columnName));
            addGenColumn.setBigJavaField(StringUtils.capitalize(columnName));
            Boolean primary = columnVo.getPrimary();
            addGenColumn.setPrimary(primary);
            addGenColumn.setIncrement(columnVo.getIncrement());
            addGenColumn.setRequired(columnVo.getRequired());
            addGenColumn.setUnique(primary || !GeneratorUtils.arraysContains(GeneratorConstants.COLUMN_NAME_NOT_LIST, columnVo.getName()));
            addGenColumn.setInsert(!primary && !GeneratorUtils.arraysContains(GeneratorConstants.COLUMN_NAME_NOT_INSERT, columnVo.getName()));
            addGenColumn.setEdit(!GeneratorUtils.arraysContains(GeneratorConstants.COLUMN_NAME_NOT_EDIT, columnVo.getName()));
            addGenColumn.setList(!GeneratorUtils.arraysContains(GeneratorConstants.COLUMN_NAME_NOT_LIST, columnVo.getName()));
            addGenColumn.setQuery(!GeneratorUtils.arraysContains(GeneratorConstants.COLUMN_NAME_NOT_QUERY, columnVo.getName()));
            addGenColumn.setQueryType(GeneratorUtils.getQueryType(columnVo.getName()));
            addGenColumn.setHtmlType(GeneratorUtils.getHtmlType(columnVo.getColumnType(), columnVo.getName()));
            addGenColumn.setLayoutType("12");
            addGenColumn.setDictCode(null);
            addGenColumn.setSort(columnVo.getSort());
            addGenColumn.setRemark(columnVo.getComment());
            addGenColumnList.add(addGenColumn);
        });
        addGenRow.setAddGenColumnList(addGenColumnList);
        return addGenRow;
    }

    public static VelocityContext initVelocityContext(GenRowVo genRowVo) {
        GenColumnVo primaryGenColumnVo = genRowVo.getPrimaryGenColumnVo();
        if (ObjectUtil.isEmpty(primaryGenColumnVo))
            throw new RuntimeException("主键列不能为空");
        List<GenColumnVo> genColumnVoList = genRowVo.getGenColumnVoList();
        String markDictCodeList = getDictCodeList(genRowVo, true);
        String dictCodeList = getDictCodeList(genRowVo, false);
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("genRowVo", genRowVo);
        velocityContext.put("genColumnVoList", genColumnVoList);
        velocityContext.put("primarySysColumnVu", primaryGenColumnVo);
        velocityContext.put("securityUser", SecurityUtils.getUserInfo());
        velocityContext.put("importList", getImportList(genRowVo));
        velocityContext.put("datetime", DateUtil.now());
        velocityContext.put("authPrefix", GeneratorUtils.getAuthPrefix(genRowVo.getModule(), genRowVo.getBusiness()));
        velocityContext.put("uniqueCount", genColumnVoList.stream().filter(genColumnVo -> genColumnVo.getQuery() && genColumnVo.getUnique()).count());
        velocityContext.put("isUseDict", StrUtil.isNotEmpty(dictCodeList));
        velocityContext.put("dictCodeList", dictCodeList);
        velocityContext.put("markDictCodeList", markDictCodeList);
        setMenuInfoToVelocityContext(velocityContext, genRowVo, true);
        // 子表
        if (StrUtil.isNotEmpty(genRowVo.getChildRowId()) && StrUtil.isNotEmpty(genRowVo.getChildColumnId())) {
            GenRowVo childGenRowVo = genRowVo.getChildRowVo();
            if (ObjectUtil.isEmpty(childGenRowVo))
                throw new RuntimeException("子表信息不能为空");
            GenColumnVo childGenColumnVo = genRowVo.getChildGenColumnVo();
            if (ObjectUtil.isEmpty(childGenColumnVo))
                throw new RuntimeException("关联子表列信息不能为空");
            GenColumnVo childPrimaryGenColumnVo = childGenRowVo.getPrimaryGenColumnVo();
            if (ObjectUtil.isEmpty(childPrimaryGenColumnVo))
                throw new RuntimeException("子表主键列不能为空");
            List<GenColumnVo> childGenColumnVoList = childGenRowVo.getGenColumnVoList();
            if (ObjectUtil.isEmpty(childGenColumnVoList))
                throw new RuntimeException("子表列信息不能为空");
            String childMarkDictCodeList = getDictCodeList(childGenRowVo, true);
            String childDictCodeList = getDictCodeList(childGenRowVo, false);
            velocityContext.put("childGenRowVo", childGenRowVo);
            velocityContext.put("childGenColumnVo", childGenColumnVo);
            velocityContext.put("childAuthPrefix", GeneratorUtils.getAuthPrefix(childGenRowVo.getModule(), childGenRowVo.getBusiness()));
            velocityContext.put("childGenColumnVoList", childGenColumnVoList);
            velocityContext.put("childUniqueCount", childGenColumnVoList.stream().filter(genColumnVo -> genColumnVo.getQuery() && genColumnVo.getUnique()).count());
            velocityContext.put("childPrimaryGenColumnVo", childPrimaryGenColumnVo);
            velocityContext.put("childMarkDictCodeList", childMarkDictCodeList);
            velocityContext.put("childDictCodeList", childDictCodeList);
            velocityContext.put("childIsUseDict", StrUtil.isNotEmpty(childDictCodeList));
            setMenuInfoToVelocityContext(velocityContext, childGenRowVo, false);
        }
        return velocityContext;
    }

}
